/////////////////////////////////////////////////////////////////////
//
//  MOE Framework (Meta Object Encapsulation Framework)
//
//  Original Author: Wiksy Wang, 2011
//
/////////////////////////////////////////////////////////////////////

#ifndef MOE_RAW_BYTE_VECTOR_H
#define MOE_RAW_BYTE_VECTOR_H

#include <boost/functional/hash.hpp>

namespace MOE
{

// Custom "string" class that can take either any char string type and store them as
// a uniform byte array.
// This is so that most of our codes don't need a template parameter of string type,
// and can be normal C code.
class RawByteVector
{
public:
	// Statics

	static const RawByteVector gEmptyStr;

	// Typedefs

	typedef char value_type;
	typedef size_t difference_type;

	// Basic Functions

	// Default constructor
	RawByteVector();

	// Standard constructor
	template <class StringType>
	RawByteVector(const StringType& str)
	{
		ToRawBytes(str, _length, _bytes);
	}

	// Copy constructor
	RawByteVector(const RawByteVector& other);

	// Copy operator
	RawByteVector& operator=(const RawByteVector& other);

	// Destructor
	~RawByteVector();

	bool empty() const { return _length == 0; }
	size_t size() const { return _length; }
	value_type* data() const { return _bytes; }

	void resize(size_t length);

	template <class CharType>
	const CharType* to_ptr() const
	{
		return reinterpret_cast<const CharType*>(_bytes);
	}

	template <class CharContainerType>
	CharContainerType to_string() const
	{
		typedef CharContainerType::value_type CharType;
		CharContainerType tmpResult;
		if (_length > 0)
		{
			tmpResult.resize((_length * sizeof(value_type) + sizeof(CharType) - sizeof(value_type)) / sizeof(CharType));
			memcpy(&tmpResult[0], _bytes, _length * sizeof(value_type));
		}
		return tmpResult;
	}

	// Operators

	bool operator==(const RawByteVector& other) const
	{
		if (_length != other._length) return false;
		if (_length == 0) return true;
		return (_memicmp(_bytes, other._bytes, _length) == 0);
	}

	bool operator<(const RawByteVector& other) const
	{
		if (_length < other._length) return true;
		if (_length > other._length) return false;
		if (_length == 0) return false;
		return (_memicmp(_bytes, other._bytes, _length) < 0);
	}

	bool operator<=(const RawByteVector& other) const
	{
		if (_length < other._length) return true;
		if (_length > other._length) return false;
		if (_length == 0) return true;
		return (_memicmp(_bytes, other._bytes, _length) <= 0);
	}

	bool operator!=(const RawByteVector& other) const
	{
		return !(*this == other);
	}

	bool operator>(const RawByteVector& other) const
	{
		return (other < *this);
	}

	bool operator>=(const RawByteVector& other) const
	{
		return (other <= *this);
	}

private:
	size_t _length;
	value_type* _bytes;

	friend class RawByteVectorRef;
};

template <class T>
void ToRawBytes(const T& str, size_t& out_length, char*& out_bytes);

template <class CharType>
void ToRawBytes(const CharType* const str, size_t& out_length, char*& out_bytes)
{
	const CharType* current = str;
	while (*current != 0)
	{
		++current;
	}
	out_length = (current - str) * (sizeof(CharType) / sizeof(char));
	if (out_length)
	{
		out_bytes = new char[out_length];
		memcpy(out_bytes, str, out_length * sizeof(char));
	}
	else
	{
		out_bytes = NULL;
	}
}

template <class CharContainerType>
void ToRawBytes(const CharContainerType& str, size_t& out_length, char*& out_bytes)
{
	typedef typename CharContainerType::value_type CharType;
	out_length = str.size() * (sizeof(CharType) / sizeof(char));
	if (out_length)
	{
		out_bytes = new char[out_length];
		memcpy(out_bytes, str.data(), out_length * sizeof(char));
	}
	else
	{
		out_bytes = NULL;
	}
}

inline size_t hash_value(const RawByteVector& str)
{
	return boost::hash_range(str.data(), str.data() + str.size());
}

}

#endif
